package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"strconv"
	"syscall"
)

const cgroupMemoryHierarchyMount = "/sys/fs/cgroup/memory"

func main() {
	var (
		err error
	)

	if os.Args[0] == "/proc/self/exe" {
		fmt.Println("it is a container")
	}

	cmd := exec.Command("/proc/self/exe")
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS,
	}

	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	if err = cmd.Start(); err != nil {
		fmt.Println("error happen:", err)
		return
	}

	//no error,get fork process pid in outer namespace
	fmt.Printf("%v", cmd.Process.Pid)

	newCGroupDir := path.Join(cgroupMemoryHierarchyMount, "testmemorylimit")
	os.Mkdir(newCGroupDir, 0755)

	//write pid to tasks file
	tasksPath := path.Join(newCGroupDir, "tasks")
	data := strconv.Itoa(cmd.Process.Pid)
	if err := ioutil.WriteFile(tasksPath, []byte(data), 0644); err != nil {
		fmt.Println("set pid to cgroup failed:", err)
		return
	}

	//limit resource of the process in cgroup
	if err := ioutil.WriteFile(path.Join(newCGroupDir, "memory.limit_in_bytes"), []byte("100m"), 0644); err != nil {
		fmt.Println("set 100m memory limit failed:", err)
		return
	}

	//wait process
	cmd.Process.Wait()
}
